home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-06-23 | 9.0 KB | 353 lines | [TEXT/CWIE] |
- #include "CFlock.h"
- #include "FlockDrawing.h"
-
- // a sick hack for key control of the flock
- ControlRec gCurrentControls;
- Boolean gControlsChanged;
- long timer;
-
- extern long gNumItems;
- extern Handle gIcons[];
- extern Handle gMasks[];
- extern Point gPositions[];
-
- CFlock::CFlock(void)
- {
- short cnt;
-
- for(cnt = 0; cnt < kMaxBoids; cnt++)
- fTheBoids[cnt] = nil; // array of boids
- }
-
- CFlock::~CFlock(void)
- {
- }
-
- CFlock* CFlock :: InitFlock(RgnHandle blankRgn)
- {
- short cnt;
- Handle hVals;
-
- HLock((Handle)this);
-
- /* Get the controls from the FCTL resource for this flock type */
- this->fControls.fNumBoidsCtl = gNumItems;
-
- // •• leftovers
- this->fControls.fBoidTypeCtl = 8;
- GetNewControls(&this->fControls, this->fControls.fBoidTypeCtl);
- this->fControls.fMaxVelocityCtl = 0;
- this->fControls.fMaxAccelCtl = 0;
-
- // !!! stash them everywhere
- this->fGoodControls = gCurrentControls = this->fControls;
-
- // set correct screen rect
- this->fMasterFlockRect = (**blankRgn).rgnBBox;
-
- /* Set up some fields in the flock structure for easy reference */
- this->fNumBoids = fGoodControls.fNumBoidsCtl;
- this->fMaxEffort = fGoodControls.fMaxEffortCtl;
-
- /* Adjust the flockrect to the boid size */
- this->fFlockRect = this->fMasterFlockRect;
- this->fFlockRect.right -= 32; // !•
- this->fFlockRect.bottom -= 32;// !•
-
- /* Do the Aware distance processing */
- this->fAwareDist = this->fGoodControls.fAwareDistCtl;
- this->fAwareDistSquared = this->fAwareDist * this->fAwareDist;
-
- /* Do the comfy distance processing */
- this->fComfyDist = this->fGoodControls.fComfyDistCtl;
- this->fComfyDistSquared = this->fComfyDist * this->fComfyDist;
-
- // Now init a boid for each item
- for (cnt = 0; cnt < this->fNumBoids; cnt++)
- {
- fTheBoids[cnt] = ((CBoid *)new(CBoid))->InitBoid(&this->fFlockRect,
- gIcons[cnt], gMasks[cnt], gPositions[cnt]);
-
- if(fTheBoids[cnt] == nil)
- {
- short donecount;
- Str255 errstr;
-
- // Kill the boids already inited
- for(donecount = 0; donecount < cnt; donecount++)
- delete(fTheBoids[donecount]);
-
- HUnlock((Handle)this);
- return nil;
- }
- }
-
- // Made it!
- HUnlock((Handle)this);
-
- //Start with zero velocity
- timer = TickCount();
- return(this);
- }
-
- OSErr CFlock :: FlockStep(RgnHandle blankRgn)
- {
- short cnt, rand, err;
- FloatPoint dummy;
-
- // Ramp up at the start
- if(gCurrentControls.fMaxVelocityCtl == 0)
- {
- if(TickCount() - timer > 180)
- {
- gCurrentControls.fMaxVelocityCtl = 1;
- gCurrentControls.fMaxAccelCtl = 1;
- this->ControlsChanged(&gCurrentControls, blankRgn);
- timer = TickCount();
- }
- }
- else if(TickCount() - timer > 60 && gCurrentControls.fMaxAccelCtl < 5)
- {
- gCurrentControls.fMaxVelocityCtl += 2;
- gCurrentControls.fMaxAccelCtl += 1;
- timer = TickCount();
- this->ControlsChanged(&gCurrentControls, blankRgn);
- }
-
- // Set the port to sprocket context
- err = StartDrawing();
- if(err) return err;
-
- // if fNumBoids > zero and no error, continue
- if( (fNumBoids > 0) && (err == noErr) )
- {
- // Here's where the NeighborRecords get filled in
- this->FindNeighbors();
-
- // Now that the Neighbors are all recorded, we can move each boid
- for(cnt = 0; cnt < fNumBoids; cnt++)
- {
- this->fTheBoids[cnt]->Move(
- &dummy,
- &this->fFlockRect,
- &this->fGoodControls,
- this->fComfyDistSquared );
- }
- }
-
- // Draw the control values, too
- //DrawControlValues(&this->fMasterFlockRect);
-
- // Done drawing
- err = EndDrawing();
-
- return err;
- }
-
- void CFlock::ShakeFlock(void)
- {
- // Randomize directions for a few frames
- }
-
- void CFlock::KillFlock(RgnHandle blankRgn)
- {
- short cnt;
-
- // Fly home
- this->FlyHome(blankRgn);
-
- // Kill all the boids
- for (cnt = 0; cnt < kMaxBoids; cnt++)
- {
- delete(this->fTheBoids[cnt]);
- fTheBoids[cnt] = nil;
- }
- }
-
- // This routine processes the raw (0 - 100) controls into good
- // ones, and changes some stuff accordingly
- OSErr CFlock :: ControlsChanged(ControlRec *newControls, RgnHandle blankRgn)
- {
- OSErr err = noErr;
-
- StartDrawing(); // in case of erasing or redrawing
-
- // !!! Should remove fGoodControls, not needed any more (maybe)
- this->fGoodControls = this->fControls = *newControls;
-
- // If the comfy distance has changed, deal with it
- if(this->fGoodControls.fComfyDistCtl != this->fComfyDist)
- {
- this->fComfyDist = this->fGoodControls.fComfyDistCtl;
- this->fComfyDistSquared = this->fComfyDist * this->fComfyDist;
- }
-
- // If the AwareDist has changed, deal with it
- if(this->fGoodControls.fAwareDistCtl != this->fAwareDist)
- {
- this->fAwareDist = this->fGoodControls.fAwareDistCtl;
- this->fAwareDistSquared = this->fAwareDist * this->fAwareDist;
- }
-
- // Swap Buffers in case there was drawing (or erasing
- err = EndDrawing();
-
- return err;
- }
-
-
- void CFlock :: FindNeighbors(void)
- {
- CBoid **thisboid, **thatboid, **lastboid;
- double dist;
- FloatPoint thisPos, thatPos, thisVel, thatVel;
-
- // Set up
- thisboid = &fTheBoids[0];
- lastboid = &fTheBoids[fNumBoids - 1];
- dist = this->fAwareDist;
-
-
- do // for all boids
- {
- if(thisboid == lastboid) // To prevent an endless loop
- continue;
- thatboid = thisboid;
- (*thisboid)->GetBoidPos(&thisPos);
- (*thisboid)->GetBoidVel(&thisVel);
-
- // This loop looks at each boid "below" thisboid in the list
- while(thatboid++ != lastboid)
- {
- double sqdist;
- double diffh, diffv;
-
- (*thatboid)->GetBoidPos(&thatPos);
-
- // Check, x, then y
- diffh = thatPos.h - thisPos.h;
- if(fabs(diffh) > dist)
- continue;
-
- diffv = thatPos.v - thisPos.v;
- if(fabs(diffv) > dist)
- continue;
-
- // Compute the distance squared between this pair of boids
- sqdist = VecMagSq(diffh, diffv);
-
- // If close enough, add to neighbors of both boids
- if(sqdist < this->fAwareDistSquared)
- {
- // Get the velocity of that boid, now that we know we'll need it
- (*thatboid)->GetBoidVel(&thatVel);
-
- // -----------------------
- // Look from this to that
- // -----------------------
- if((*thisboid)->fNaybs.fNum == 0) // First neighbor for this boid
- {
- (*thisboid)->fNaybs.fAvgPos = thatPos;
- (*thisboid)->fNaybs.fAvgVel = thatVel;
- }
- else // Average in this neighbor with the others
- {
- TwoVecAvg(&((*thisboid)->fNaybs.fAvgPos), &thatPos);
- TwoVecAvg(&((*thisboid)->fNaybs.fAvgVel), &thatVel);
- }
- // the neighbors' average distance is the difference between thisPos
- // and the average position
- (*thisboid)->fNaybs.fAvgDistSquared =
- VecMagSq( thisPos.h - ((*thisboid)->fNaybs.fAvgPos).h,
- thisPos.v - ((*thisboid)->fNaybs.fAvgPos).v );
-
- // if the distance between these boids is less than the nearest neighbor,
- // then thatboid is our new nearest neighbor
- if(sqdist < (*thisboid)->fNaybs.fNearestDistSquared)
- {
- (*thisboid)->fNaybs.fNearestDistSquared = sqdist;
- (*thisboid)->fNaybs.fNearestPos = thatPos;
- }
-
- // Remember to increment number of neighbors
- (*thisboid)->fNaybs.fNum++;
-
- // -----------------------
- // Look from that to this
- // -----------------------
- if((*thatboid)->fNaybs.fNum == 0) // First neighbor for that boid
- {
- ((*thatboid)->fNaybs.fAvgPos) = thisPos;
- ((*thatboid)->fNaybs.fAvgVel) = thisVel;
- }
- else // Average in this neighbor with the others
- {
- TwoVecAvg(&((*thatboid)->fNaybs.fAvgPos), &thisPos);
- TwoVecAvg(&((*thatboid)->fNaybs.fAvgVel), &thisVel);
- }
- // the neighbors' average distance is the difference between thatPos
- // and the average position
- (*thatboid)->fNaybs.fAvgDistSquared =
- VecMagSq( thatPos.h - ((*thatboid)->fNaybs.fAvgPos).h,
- thatPos.v - ((*thatboid)->fNaybs.fAvgPos).v );
-
- // if the distance between these boids is less than the nearest neighbor,
- // then thisboid is our new nearest neighbor
- if(sqdist < (*thatboid)->fNaybs.fNearestDistSquared)
- {
- (*thatboid)->fNaybs.fNearestDistSquared = sqdist;
- (*thatboid)->fNaybs.fNearestPos = thisPos;
- }
-
- // Remember to increment number of neighbors
- (*thatboid)->fNaybs.fNum++;
-
- } // if in range
- } // while
- }while(thisboid++ != lastboid);
- }
-
- void CFlock :: FlyHome(RgnHandle blankRgn)
- {
- short cnt, cnt2;
- FloatPoint dummy;
- Boolean done = false;
- long ticks;
-
- // Set the controls to center only
- gCurrentControls.fAwareDistCtl = 20000;
- gCurrentControls.fComfyDistCtl = 1;
- gCurrentControls.fAvoidMaxCtl = 0;
- gCurrentControls.fMatchMaxCtl = 0;
- gCurrentControls.fCenterMaxCtl = 10;
- gCurrentControls.fMaxEffortCtl = 10;
- gCurrentControls.fMaxAccelCtl = 2;
- gCurrentControls.fMaxVelocityCtl = 5;
- this->ControlsChanged(&gCurrentControls, blankRgn);
-
- // go home
- ticks = TickCount();
- while(!done)
- {
- done = true;
- StartDrawing();
- for(cnt = 0; cnt < fNumBoids; cnt++)
- {
- if(!this->fTheBoids[cnt]->HeadHome()) // if anyone's not home yet, keep going
- {
- if(TickCount() - ticks > 600)
- this->fTheBoids[cnt]->fHome = true;
- done = false;
- }
- this->fTheBoids[cnt]->Move(
- &dummy,
- &this->fFlockRect,
- &this->fGoodControls,
- this->fComfyDistSquared );
- }
- EndDrawing();
-
- }
- // let everyone see
- Delay(60, &ticks);
- }